Unite 2019 |《球球大作战》优化之路(下)
上一篇我们分享了《球球大作战》优化之路客户端主程王国祎部分,本文将继续由资深技术徐宇峰讲述后期游戏制作中的优化方式。
演讲内容
大家好,我叫徐宇峰,负责《球球大作战》的性能优化。
《球球大作战》现在拥有五亿多的玩家,为了吸引如此庞大的玩家群体,我们提供给玩家更炫更酷的皮肤,这些美轮美奂的皮肤,让《球球大作战》的游戏画面更加绚丽多彩,但随着皮肤日益精致,性能问题开始日益突出。
我们的皮肤正面看起来很简单,从侧面看,皮肤由精美模型与很多特效层组合而成。
皮肤的材质大部分为半透明。大量的半透明材质无法合批渲染,导致单套皮肤Draw Calls达到82个,面数1.1万以及骨骼40个。
《球球大作战》最核心技能就是分身吃球,而当玩家分身之后,Draw Calls更是暴涨,游戏中玩家最大16分身时,Draw Calls有820多,面数达17.7万。
在实际游戏中,多玩家多皮肤分身后,Draw Calls经常能轻松过千,下面视频是我们内部的极限测试版情况。
大家能看到,Draw Calls最低有400-500,最高达到2000多, 如此高的Draw Calls导致游戏的帧率急剧下降,卡顿严重。而球球作为一款竞技游戏,性能与体验至关重要。
我们团队采用各种优化方法:
模型贴图合并:模型与贴图尽可能的合并在一起,利用Unity的动态合批渲染,减少Draw Calls。
减少半透明材质:半透明会带来融合运算,其次重叠的半透明物体无法合批渲染,导致Draw Calls增加。
减少粒子系统:粒子会增加CPU运算,还会增加Draw Calls,每套皮肤的粒子数量我们控制在40个以内.
LOD系统
降低分辨率:皮肤的贴图普遍采用512k,部分贴图在低端机器上降低到256k。
我们来看看优化对比。
下面视频是一个LOD系统的效果对比,左边是高性能机型高画质,右边是低端机型流畅画质。左右相互对比可以看到,右边的皮肤少了些特效与动画,贴图分辨率也相应降低。
通过以上优化,游戏性能大约提升52%,但画面品质同样遭受损失,在中低端机器上尤为明显,这点很容易引起玩家的不满。
美术团队也希望所有机型,画面尽可能的完美,并且过少Draw Calls极大限制了美术的高水平发挥。
《球球大作战》优化的难点是皮肤分身后Draw Calls暴涨的问题。
我们想到用RenderTexture来降低Draw Calls峰值,但皮肤有太多半透明,渲染管线中对于透明相关的处理是在管线后期进行的。由于不同物体是按照顺序渲染的,对透明的处理方式是混合,实际上就是shader输出颜色与此像素位置已有颜色的合并过程。
下图中的混合公式是Unity中最标准的混融模式Blend SrcAlpha OneMinusSrcAlpha。
假设将Camera背景的颜色设置为全黑色(0001)或全白色(1111) ,分别进行渲染,渲染后的颜色分别为Cblack、Cwhite,得到公式1和2。公式中蓝色为已知数,紫色为未知数,2个公式可以求出2个未知数。
具体代码请参考:
http://wiki.unity3d.com/index.php/AnimationToPNG
下面看看具体制作流程。
我们把原资源用单相机渲染到RenderTexture,相机每帧切换黑白背景,形成连续序列帧,这是因为单个相机能节省更多的Draw Calls,但如果动画速度过快,就必须使用双相机保证品质。
RT经过GPU做算法剔除,输出到多张RenderTexture。RT我们采用512分辨率,一共40张,格式为ARGBHalf,真机占用内存约为20兆,目前市面上主流手机内存大部分为2G以上,所以内存很充足。具体用到那种分辨率与RT数量的多少,需要根据不同机型做适当调整。
多张带RT的RenderTexture组成一套序列帧,利用Plane切换RT做成序列帧动画。序列帧会循环渲染,从RT1渲染到40,再回到第1张。
Plane读取RT时也是循环读取,最后序列帧动画放到场景中与半透明背景,半透明皮肤以及UI等进行融合。
下面我们来看看原资源与RT资源的实时效果对比。这是原素材与RenderTexture的实时效果对比,原素材由十几层特效叠加,而RenderTexture只有单个面。
大家看看不同资源的效果对比,新技术首先必须保证美术品质才能投入使用。
在美术品质保证后,再看看优化前后Draw Calls对比。
当分身不断增加时,Draw Calls以线性增长,大家可以看看下面的Draw Calls图表,从最开始63暴涨至900多。
在RT模式下,分身的增加带来Draw Calls的个位数增加,同时可以看到在RT模式下,因为我们利用多张RenderTexture,每个分身的动画帧是错开的,动画并不完全一样。
我们再看看真机数据对比,测试平台为普通千元机。
如下图所示,左图分身数从1至16,普通模式Draw Calls从63暴涨至917,翻了14.5倍,每一次分身数量的翻倍都让Draw Calls剧烈变化。而RT模式从64到83只增加19个。
有图CPU消耗图,在RT模式下,CPU的消耗非常平稳,而普通模式最大分身时消耗已经翻倍。
再来看看FPS与内存消耗。
如下图所示,帧率在普通模式下,16分身帧率已经降低到25,加上UI与其它逻辑消耗,已经产生游戏卡顿。而RT模式帧率非常平稳。
内存方面因为RT用了40张16位的512贴图,内存大约多20MB,这是RT模式唯一消耗点。实际应用中我们会根据机器的内存容量,控制RT的数量与分辨率。
《球球大作战》同屏有上千物体,每帧数千个物体的位置、大小、动画、网络数据等伴随着产生大量逻辑运算。
主要逻辑有:
利用插值函数使物体的移动更加平滑。
玩家吃球后重量会增加:根据重量来计算球的尺寸与前后位置,尺寸越大物体越靠近摄像机。
AI状态机:玩家根据游戏状态,如二个玩家距离接近时,会播放调侃动画,吃掉其他玩家时播放炫耀动画;
相机视野计算:玩家所有球的数量与尺寸变化,都伴随着相机位置与FOV调整,每个分身必须在相机视野内,最大分身尽可能处于屏幕中心;
其它逻辑:还有网络数据解压缩、解密、背景迷雾、UI运算等。
以上这么多的实时运算量会对CPU产生巨大压力。
我们利用Unity 2018的ECS系统,把所有逻辑做分类,纯逻辑运算做成PureECS,其他部分做成HybridECS。数千物体的逻辑运算,尽可能分配到多个核心。
这极大的提升游戏性能,并且更快更复杂的运算让物体的移动、旋转更加平滑和细腻,增强游戏的用户体验。
上述的优化方法,部分处于《球球大作战》的试用阶段,我们一直都在不断尝试和创新,使用各种优化方式,让《球球大作战》拥有更好的用户体验,并不断焕发新的活力!
我的演讲到此结束,谢谢大家。
小结
我们感谢《球球大作战》的创作团队给带来的精彩分享。更多Unite大会精彩内容分享,尽在Unity Connect平台(Connect.unity.com)。
下载Unity Connect APP,请点击此处。 观看部分Unity官方视频,请关注B站帐户:Unity官方。
推荐阅读
Unite 2019 | Unity中的实时光线追踪技术剖析
使用Unity 2019.1中的Timeline Signals
有奖调查
Unity Hub 2.0中文版以及Unity中文版文档已发布,请参与有奖调查,反馈你的意见,以便我们进一步改进。更多详情,请访问此处。
点击“阅读原文”访问Unity Connect